package com.tsfyun.scm.service.impl.order;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.itextpdf.text.*;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.tsfyun.common.base.dto.ExportFileDTO;
import com.tsfyun.common.base.enums.*;
import com.tsfyun.common.base.enums.domain.DomainOprationEnum;
import com.tsfyun.common.base.enums.domain.MaterielStatusEnum;
import com.tsfyun.common.base.enums.domain.PaymentAccountStatusEnum;
import com.tsfyun.common.base.enums.domain.RiskApprovalStatusEnum;
import com.tsfyun.common.base.enums.finance.CostClassifyEnum;
import com.tsfyun.common.base.enums.risk.RiskApprovalDocTypeEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.support.DomainStatus;
import com.tsfyun.common.base.util.DateUtils;
import com.tsfyun.common.base.util.LocalDateTimeUtils;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.common.base.validator.ValidatorUtils;
import com.tsfyun.scm.base.DataCalling;
import com.tsfyun.scm.base.entity.OperationMaintenance;
import com.tsfyun.scm.entity.customer.*;
import com.tsfyun.scm.entity.finance.PaymentAccount;
import com.tsfyun.scm.entity.order.ImpOrder;
import com.tsfyun.scm.entity.order.ImpOrderCost;
import com.tsfyun.scm.entity.order.ImpOrderMember;
import com.tsfyun.scm.entity.risk.RiskApproval;
import com.tsfyun.scm.mapper.order.ImpOrderCostMapper;
import com.tsfyun.scm.service.base.ISystemCacheService;
import com.tsfyun.scm.service.customer.*;
import com.tsfyun.scm.service.file.IExportFileService;
import com.tsfyun.scm.service.finance.IPaymentAccountMemberService;
import com.tsfyun.scm.service.finance.IPaymentAccountService;
import com.tsfyun.scm.service.finance.IReceiptAccountService;
import com.tsfyun.scm.service.order.IImpOrderCostService;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.scm.service.order.IImpOrderMemberService;
import com.tsfyun.scm.service.order.IImpOrderService;
import com.tsfyun.scm.service.risk.IRiskApprovalService;
import com.tsfyun.scm.service.system.ISubjectBankService;
import com.tsfyun.scm.service.system.ISubjectService;
import com.tsfyun.scm.system.vo.CountryVO;
import com.tsfyun.scm.system.vo.CustomsCodeVO;
import com.tsfyun.scm.util.AccountUtils;
import com.tsfyun.scm.util.ExpressQuoteUtil;
import com.tsfyun.scm.util.TsfWeekendSqls;
import com.tsfyun.scm.vo.finance.PaymentAccountMemberVO;
import com.tsfyun.scm.vo.finance.PaymentCostInfoVO;
import com.tsfyun.scm.vo.finance.PaymentOrderCostVO;
import com.tsfyun.scm.vo.order.*;
import com.tsfyun.scm.vo.system.SubjectBankVO;
import com.tsfyun.scm.vo.system.SubjectSimpleVO;
import jxl.Workbook;
import jxl.format.Alignment;
import jxl.format.UnderlineStyle;
import jxl.format.VerticalAlignment;
import jxl.write.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.io.File;
import java.io.FileOutputStream;
import java.lang.Boolean;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单费用 服务实现类
 * </p>
 *
 *
 * @since 2020-04-21
 */
@RefreshScope
@Service
@Slf4j
public class ImpOrderCostServiceImpl extends ServiceImpl<ImpOrderCost> implements IImpOrderCostService {

    @Autowired
    private IReceiptAccountService receiptAccountService;
    @Autowired
    private IImpClauseService impClauseService;
    @Autowired
    private IImpQuoteService impQuoteService;
    @Autowired
    private IAgreementService agreementService;
    @Autowired
    private IImpOrderMemberService impOrderMemberService;
    @Autowired
    private IImpOrderService impOrderService;
    @Autowired
    private ISystemCacheService systemCacheService;
    @Autowired
    private Snowflake snowflake;
    @Autowired
    private ImpOrderCostMapper impOrderCostMapper;
    @Autowired
    private ICustomerService customerService;
    @Autowired
    private IRiskApprovalService riskApprovalService;
    @Autowired
    private ISubjectService subjectService;
    @Autowired
    private ISubjectBankService subjectBankService;
    @Autowired
    private IPaymentAccountService paymentAccountService;
    @Autowired
    private IPaymentAccountMemberService paymentAccountMemberService;
    @Autowired
    private ICustomerExpressQuoteService customerExpressQuoteService;
    @Autowired
    private ICustomerExpressQuoteMemberService customerExpressQuoteMemberService;
    @Autowired
    private IExportFileService exportFileService;
    @Value("${file.directory}")
    private String filePath;
    @Value("${transInsuranceFee.dividing}")
    private BigDecimal transInsuranceFeeDividing;
    @Value("${transInsuranceFee.price}")
    private BigDecimal transInsuranceFeePrice;
    @Value("${transInsuranceFee.rate}")
    private BigDecimal transInsuranceFeeRate;
    @Value("${customsTax.dividing}")
    private BigDecimal customsTaxDividing;
    @Value("${customsTax.price}")
    private BigDecimal customsTaxPrice;
    @Value("${customsTax.rate}")
    private BigDecimal customsTaxRate;

    @Override
    public void calculationCost(ImpOrder impOrder) {
        calculationCost(impOrder, LocalDateTimeUtils.convertLocalDate());
    }

    /**=
     * 订单费用计算
     * @param impOrder
     * @param orderDate
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void calculationCost(ImpOrder impOrder, LocalDateTime orderDate) {
        impOrder.setOrderDate(orderDate);

        // impOrder.setOrderDate(LocalDateTimeUtils.parse("2021-04-01 00:00:00","yyyy-MM-dd HH:mm:ss"));
        //获取海关汇率
        BigDecimal customsRate = DataCalling.getInstance().obtainCustomsRate(impOrder.getCurrencyId(),impOrder.getOrderDate());
        TsfPreconditions.checkArgument(Objects.nonNull(customsRate),new ServiceException("未取到有效海关汇率请稍后重试"));
        impOrder.setCustomsRate(customsRate);//写入海关汇率
        //计算转美金汇率
        if("USD".equals(impOrder.getCurrencyId())){
            impOrder.setUsdRate(BigDecimal.ONE);//美金转换汇率
        }else{
            BigDecimal CNYRate = BigDecimal.ONE;//人民币汇率
            if(!"CNY".equals(impOrder.getCurrencyId())){
                CNYRate = impOrder.getCustomsRate();
            }
            impOrder.setUsdRate(CNYRate.divide(DataCalling.getInstance().obtainCustomsRate("USD",impOrder.getOrderDate()),8,BigDecimal.ROUND_HALF_UP));
        }

        //获取协议报价
        ImpQuote impQuote = impQuoteService.getById(impOrder.getImpQuoteId());
        //验证协议是否有效
        Agreement agreement = agreementService.validationAgreement(impQuote.getAgreementId());
        TsfPreconditions.checkArgument(Objects.nonNull(agreement),new ServiceException("当前客户协议报价已经失效，请退回重新选择"));
        //获取协议约定
        ImpClause impClause = impClauseService.getById(impQuote.getAgreementId());
        //根据约定计算结算汇率
        RateTypeEnum rateType = RateTypeEnum.of(impClause.getTaxRate());
        switch (rateType){
            case IMP_CUSTOMS://报关日海关汇率
                impOrder.setImpRate(impOrder.getCustomsRate());
                break;
            case IMP_BANK_CHINA_SELL://报关日牌价卖出价
                //获取牌价卖出价
                String rateTime = LocalDateTimeUtils.convertLocalAddHourMinuteStr(impOrder.getOrderDate(),impClause.getTaxRateTime());
                BigDecimal chinaRate = DataCalling.getInstance().obtainBankChinaRate(impOrder.getCurrencyId(),rateType.getCode(),rateTime);
                TsfPreconditions.checkArgument(Objects.nonNull(chinaRate),new ServiceException(String.format("%s【%s】暂未公布请稍后重试",rateType.getName(),impClause.getTaxRateTime())));
                impOrder.setImpRate(chinaRate);
                break;
            default:
                throw new ServiceException("协议约定税款结算汇率错误");
        }
        //根据业务类型获取税点
        BusinessTypeEnum businessType = BusinessTypeEnum.of(impOrder.getBusinessType());
        BigDecimal taxPoint = DataCalling.getInstance().obtainTaxPoint(businessType); //税点
        BigDecimal totalTariffRateVal = BigDecimal.ZERO;//总关税
        BigDecimal totalAddedTaxTateVal = BigDecimal.ZERO;//总增值税
        BigDecimal totalExciseTaxVal = BigDecimal.ZERO;//总消费税
        //订单成交方式
        TransactionModeEnum transactionMode = TransactionModeEnum.of(impOrder.getTransactionMode());
        BigDecimal cifRate = BigDecimal.ZERO;//CIF运保费率
        List<OperationMaintenance> fobRates = Lists.newArrayList();//FOB运保费率
        switch (transactionMode){
            case CIF:
                cifRate = DataCalling.getInstance().impCIFRate();
                impOrder.setTransCosts("");//运费
                impOrder.setInsuranceCosts("");//保费
                impOrder.setMiscCosts("");//杂费
                break;
            case FOB:
                List<String> stringList;
                if(StringUtils.isEmpty(impOrder.getTransCosts())){
                    stringList = DataCalling.getInstance().impFOBRateStr();

                    impOrder.setTransCosts(stringList.get(0));//运费
                    impOrder.setInsuranceCosts(stringList.get(1));//保费
                    impOrder.setMiscCosts(stringList.get(2));//杂费
                }else{
                    stringList = new ArrayList<String>(){{
                        add(impOrder.getTransCosts());
                        add(impOrder.getInsuranceCosts());
                        add(impOrder.getMiscCosts());
                    }};
                }
                List<OperationMaintenance>  maintenanceList = DataCalling.getInstance().formatImpFOBRateStr(stringList);
                maintenanceList.stream().forEach(im ->{
                    //不是按比例，并且币制不是人民币，需要根据海关汇率转换
                    if(im.getType()!=1&&!"CNY".equals(im.getCurrency())){
                        BigDecimal crate = DataCalling.getInstance().obtainCustomsRate(im.getCurrency(),impOrder.getOrderDate());
                        im.setVal(im.getVal().multiply(crate).setScale(10,BigDecimal.ROUND_HALF_UP));
                    }
                });
                fobRates.add(maintenanceList.get(2));//杂费
                fobRates.add(maintenanceList.get(0));//运费
                fobRates.add(maintenanceList.get(1));//保费
                break;
            default:
                throw new ServiceException("成交方式错误");
        }
        //获取包含归类物料的产品信息
        List<ImpOrderMemberVO> impOrderMemberVOS = impOrderMemberService.findOrderMaterielMember(impOrder.getId());
        //更新的订单明细
        List<ImpOrderMember> updateMemberList = Lists.newArrayList();
        //存储海关编码
        Map<String,CustomsCodeVO> hsCodeMap = Maps.newHashMap();
        //储存国家数据
        Map<String, CountryVO> countryMap = Maps.newHashMap();

        BigDecimal rtotalDecTotalPrice = BigDecimal.ZERO;
        BigDecimal totalDecTotalPrice = BigDecimal.ZERO;
        for(ImpOrderMemberVO vo : impOrderMemberVOS){
            rtotalDecTotalPrice = rtotalDecTotalPrice.add(vo.getDecTotalPrice().multiply(impOrder.getCustomsRate()).setScale(20,BigDecimal.ROUND_HALF_UP));
            totalDecTotalPrice = totalDecTotalPrice.add(vo.getDecTotalPrice().multiply(impOrder.getImpRate()).setScale(20,BigDecimal.ROUND_HALF_UP));
        }
        for(ImpOrderMemberVO vo : impOrderMemberVOS){
            //物料未归类
            if (!Objects.equals(MaterielStatusEnum.of(vo.getMaterielStatusId()), MaterielStatusEnum.CLASSED)) {
                throw new ServiceException(String.format("第【%d】行：型号【%s】还未完成归类", vo.getRowNo(), vo.getModel()));
            }
            //同步产品信息
            ImpOrderMember iom = new ImpOrderMember();
            iom.setId(vo.getId());
            iom.setName(vo.getDecName());
            iom.setBrand(vo.getDecBrand());

            //完税价格(实缴)
            BigDecimal rdutyPaidVal = BigDecimal.ZERO;
            //完税价格(应收)
            BigDecimal dutyPaidVal = BigDecimal.ZERO;
            switch (transactionMode){
                case CIF:
                    //完税金额 = 保留0位小数四舍五入（保留1位小数向下（保留2位小数四舍五入（货值*1.0015）* 海关汇率））
                    rdutyPaidVal = vo.getDecTotalPrice().multiply(impOrder.getCustomsRate()).setScale(1,BigDecimal.ROUND_DOWN).setScale(0,BigDecimal.ROUND_HALF_UP);

                    dutyPaidVal = vo.getDecTotalPrice().multiply(impOrder.getImpRate()).setScale(2,BigDecimal.ROUND_HALF_UP);
                    break;
                case FOB:
                    BigDecimal ritemDecTotalPrice = vo.getDecTotalPrice().multiply(impOrder.getCustomsRate()).setScale(20,BigDecimal.ROUND_HALF_UP);
                    BigDecimal itemDecTotalPrice = vo.getDecTotalPrice().multiply(impOrder.getImpRate()).setScale(20,BigDecimal.ROUND_HALF_UP);
                    rdutyPaidVal = ritemDecTotalPrice;
                    dutyPaidVal = itemDecTotalPrice;
                    for( OperationMaintenance om : fobRates){
                        if(om.getType()==3){//总价
                            //计算出分摊金额
                            BigDecimal rshare =  ritemDecTotalPrice.divide(rtotalDecTotalPrice,20,BigDecimal.ROUND_HALF_UP).multiply(om.getVal()).setScale(20,BigDecimal.ROUND_HALF_UP);
                            BigDecimal share =  itemDecTotalPrice.divide(totalDecTotalPrice,20,BigDecimal.ROUND_HALF_UP).multiply(om.getVal()).setScale(20,BigDecimal.ROUND_HALF_UP);
                            rdutyPaidVal = rdutyPaidVal.add(rshare).setScale(0,BigDecimal.ROUND_HALF_UP);
                            dutyPaidVal = dutyPaidVal.add(share).setScale(0,BigDecimal.ROUND_HALF_UP);
                        }else if(om.getType()==1){//率
                            BigDecimal rate = om.getVal().divide(BigDecimal.valueOf(100));
                            rdutyPaidVal = rdutyPaidVal.multiply(BigDecimal.ONE.add(rate)).setScale(0,BigDecimal.ROUND_HALF_UP);
                            dutyPaidVal = dutyPaidVal.multiply(BigDecimal.ONE.add(rate)).setScale(0,BigDecimal.ROUND_HALF_UP);
                        }else{
                            throw new ServiceException("不支持单价计算");
                        }
                    }
                    break;
            }
            iom.setRdutyPaidVal(rdutyPaidVal);
            iom.setDutyPaidVal(dutyPaidVal);
            //获取海关编码详情
            CustomsCodeVO customsCodeVO = hsCodeMap.get(vo.getHsCode());
            if(Objects.isNull(customsCodeVO)){
                customsCodeVO = DataCalling.getInstance().obtainHsCodeDetail(vo.getHsCode());
                hsCodeMap.put(vo.getHsCode(),customsCodeVO);
            }
            //国家
            CountryVO country = countryMap.get(vo.getCountry());
            if(Objects.isNull(country)){
                country = systemCacheService.getCountryById(vo.getCountry());
                countryMap.put(vo.getCountry(),country);
            }
            //分析关税率
            BigDecimal tariffRate = analysisTariffRate(customsCodeVO,country);
            iom.setLevyVal(BigDecimal.ZERO);
            if("USA".equals(country.getId())){
                //对美加征税率
                BigDecimal levyVal = Objects.nonNull(customsCodeVO.getLevyTax())?customsCodeVO.getLevyTax():BigDecimal.ZERO;
                iom.setLevyVal(levyVal.divide(BigDecimal.valueOf(100)));//加征税率
            }
            iom.setTariffRate(tariffRate.divide(BigDecimal.valueOf(100)).add(iom.getLevyVal()));//关税率
            iom.setAddedTaxTate(customsCodeVO.getVatr().divide(BigDecimal.valueOf(100)));//增值税率
            iom.setExciseTax(StringUtils.isEmpty(customsCodeVO.getConrate())?"0":customsCodeVO.getConrate()); //消费税率
            //关税金额 = 完税价格 * 关税税率
            iom.setRtariffRateVal(rdutyPaidVal.multiply(iom.getTariffRate()).setScale(2,BigDecimal.ROUND_HALF_UP));
            iom.setTariffRateVal(dutyPaidVal.multiply(iom.getTariffRate()).setScale(2,BigDecimal.ROUND_HALF_UP));
            BigDecimal exciseTax = BigDecimal.ZERO;//消费税率
            try{
                exciseTax = new BigDecimal(iom.getExciseTax());
            }catch (Exception e){
                exciseTax = BigDecimal.ZERO;
            }
            if(exciseTax.compareTo(BigDecimal.ZERO)==1){//存在消费税率
                iom.setExciseTax(exciseTax.divide(BigDecimal.valueOf(100)).toString());
                //消费税金额 = 保留2位小数四舍五入（完税价格 * （1 + 关税率） / (1 - 消费税率) * 消费税率）
                iom.setRexciseTaxVal(rdutyPaidVal.multiply(BigDecimal.ONE.add(iom.getTariffRate())).divide(exciseTax.multiply(BigDecimal.ONE.subtract(exciseTax)),2,BigDecimal.ROUND_HALF_UP));
                iom.setExciseTaxVal(dutyPaidVal.multiply(BigDecimal.ONE.add(iom.getTariffRate())).divide(exciseTax.multiply(BigDecimal.ONE.subtract(exciseTax)),2,BigDecimal.ROUND_HALF_UP));
                //增值税金额 = 保留2位小数四舍五入（完税价格 * (1 + 关税率) / (1 - 消费税率) * 增值税率）
                iom.setRaddedTaxTateVal(rdutyPaidVal.multiply(BigDecimal.ONE.add(iom.getTariffRate())).divide(iom.getAddedTaxTate().multiply(BigDecimal.ONE.subtract(exciseTax)),2,BigDecimal.ROUND_HALF_UP));
                iom.setAddedTaxTateVal(dutyPaidVal.multiply(BigDecimal.ONE.add(iom.getTariffRate())).divide(iom.getAddedTaxTate().multiply(BigDecimal.ONE.subtract(exciseTax)),2,BigDecimal.ROUND_HALF_UP));
            }else{//无消费税率
                iom.setExciseTax("0");
                iom.setRexciseTaxVal(BigDecimal.ZERO);
                iom.setExciseTaxVal(BigDecimal.ZERO);
                //增值税金额 = 保留2位小数四舍五入（（完税价格 + 关税金额）* 增值税率）
                iom.setRaddedTaxTateVal((rdutyPaidVal.add(iom.getRtariffRateVal())).multiply(iom.getAddedTaxTate()).setScale(2,BigDecimal.ROUND_HALF_UP));
                iom.setAddedTaxTateVal((dutyPaidVal.add(iom.getTariffRateVal())).multiply(iom.getAddedTaxTate()).setScale(2,BigDecimal.ROUND_HALF_UP));
            }
            //应收总计(税款)
            totalTariffRateVal = totalTariffRateVal.add(iom.getTariffRateVal());
            totalAddedTaxTateVal = totalAddedTaxTateVal.add(iom.getAddedTaxTateVal());
            totalExciseTaxVal = totalExciseTaxVal.add(iom.getExciseTaxVal());

            //加入修改明细
            updateMemberList.add(iom);
        }
        //记录原始
        BigDecimal  ototalTariffRateVal = totalTariffRateVal;
        BigDecimal ototalAddedTaxTateVal = totalAddedTaxTateVal;
        BigDecimal ototalExciseTaxVal = totalExciseTaxVal;
        if(impClause.getIsPaidIn()){//税款以实缴定应收
            //税金小于50不征收
            if(totalTariffRateVal.compareTo(BigDecimal.valueOf(50))==-1){totalTariffRateVal = BigDecimal.ZERO;}
            if(totalAddedTaxTateVal.compareTo(BigDecimal.valueOf(50))==-1){totalAddedTaxTateVal = BigDecimal.ZERO;}
            if(totalExciseTaxVal.compareTo(BigDecimal.valueOf(50))==-1){totalExciseTaxVal = BigDecimal.ZERO;}
        }
        //客户缴税
        if(Objects.equals(VoluntarilyTaxEnum.PARTYA,VoluntarilyTaxEnum.of(impClause.getVoluntarilyTax()))){
            totalTariffRateVal = BigDecimal.ZERO;
            totalAddedTaxTateVal = BigDecimal.ZERO;
            totalExciseTaxVal = BigDecimal.ZERO;
        }
        //税款总金额等于零，将明细置为零
        updateMemberList.stream().forEach(um ->{
            if(um.getTariffRateVal().compareTo(BigDecimal.ZERO)==0){ um.setTariffRateVal(BigDecimal.ZERO); }
            if(um.getAddedTaxTateVal().compareTo(BigDecimal.ZERO)==0){ um.setAddedTaxTateVal(BigDecimal.ZERO); }
            if(um.getExciseTaxVal().compareTo(BigDecimal.ZERO)==0){ um.setExciseTaxVal(BigDecimal.ZERO); }
        });
        List<ImpOrderCost> costList = Lists.newArrayList();
        if(greaterZero(ototalTariffRateVal)){//关税总应收
            ImpOrderCost cost = new ImpOrderCost();
            cost.setExpenseSubjectId("A0002");//科目
            cost.setCostClassify(CostClassifyEnum.SK.getCode());//分类
            cost.setActualAmount(ototalTariffRateVal);//原始金额
            cost.setReceAmount(totalTariffRateVal);//应收金额
            cost.setIsAutomatic(Boolean.TRUE);//系统生成
            cost.setOperator("系统");
            cost.setIsAllowEdit(Boolean.FALSE);//不允许修改
            costList.add(cost);
        }
        if(greaterZero(ototalAddedTaxTateVal)){//增值税总应收
            ImpOrderCost cost = new ImpOrderCost();
            cost.setExpenseSubjectId("A0003");//科目
            cost.setCostClassify(CostClassifyEnum.SK.getCode());//分类
            cost.setActualAmount(ototalAddedTaxTateVal);//原始金额
            cost.setReceAmount(totalAddedTaxTateVal);//应收金额
            cost.setIsAutomatic(Boolean.TRUE);//系统生成
            cost.setOperator("系统");
            cost.setIsAllowEdit(Boolean.FALSE);//不允许修改
            costList.add(cost);
        }
        if(greaterZero(ototalExciseTaxVal)){//消费税总应收
            ImpOrderCost cost = new ImpOrderCost();
            cost.setExpenseSubjectId("A0004");//科目
            cost.setCostClassify(CostClassifyEnum.SK.getCode());//分类
            cost.setActualAmount(ototalExciseTaxVal);//原始金额
            cost.setReceAmount(totalExciseTaxVal);//应收金额
            cost.setIsAutomatic(Boolean.TRUE);//系统生成
            cost.setOperator("系统");
            cost.setIsAllowEdit(Boolean.FALSE);//不允许修改
            costList.add(cost);
        }
        if(Objects.equals(AgencyFeeModeEnum.of(impQuote.getAgencyFeeMode()),AgencyFeeModeEnum.EXPRESS)) {
            //计算运保费
            BigDecimal cnyRate = DataCalling.getInstance().obtainCustomsRate(impOrder.getCurrencyId(),impOrder.getOrderDate());
            BigDecimal cnyGoodsValue = impOrder.getTotalPrice().multiply(cnyRate).setScale(2,BigDecimal.ROUND_HALF_UP);
            log.info("订单【{}】，人民币汇率【{}】，人民币货值【{}】计算运保费",impOrder.getDocNo(),cnyRate,cnyGoodsValue);
            BigDecimal transInsuranceFee = BigDecimal.ZERO;
            if(cnyGoodsValue.compareTo(transInsuranceFeeDividing) <= 0) {
               transInsuranceFee = transInsuranceFeePrice;
            } else {
               transInsuranceFee = transInsuranceFeePrice.add(cnyGoodsValue.multiply(transInsuranceFeeRate).setScale(2,BigDecimal.ROUND_HALF_UP));
            }
            log.info("订单【{}】，人民币汇率【{}】，人民币货值【{}】计算运保费，加税点前【{}】",impOrder.getDocNo(),cnyRate,cnyGoodsValue,transInsuranceFee);
            transInsuranceFee = transInsuranceFee.multiply(BigDecimal.ONE.add(taxPoint)).setScale(2,BigDecimal.ROUND_HALF_UP);
            log.info("订单【{}】，人民币汇率【{}】，人民币货值【{}】计算运保费，加税点后【{}】",impOrder.getDocNo(),cnyRate,cnyGoodsValue,transInsuranceFee);
            ImpOrderCost cost = new ImpOrderCost();
            cost.setExpenseSubjectId("A0035");
            cost.setCostClassify(CostClassifyEnum.DZF.getCode());//分类
            cost.setActualAmount(transInsuranceFee);//原始金额
            cost.setReceAmount(transInsuranceFee);//应收金额
            cost.setIsAutomatic(Boolean.TRUE);//系统生成
            cost.setOperator("系统");
            cost.setIsAllowEdit(Boolean.TRUE);//允许修改
            costList.add(cost);

            //香港出口海关税金
            BigDecimal customsTax;
            if(cnyGoodsValue.compareTo(customsTaxDividing) <= 0) {
                customsTax = customsTaxPrice;
            } else {
                customsTax = customsTaxPrice.add(cnyGoodsValue.multiply(customsTaxRate).setScale(2,BigDecimal.ROUND_HALF_UP));
            }
            log.info("订单【{}】，人民币汇率【{}】，人民币货值【{}】计算香港出口海关税金，加税点前【{}】",impOrder.getDocNo(),cnyRate,cnyGoodsValue,customsTax);
            customsTax = customsTax.multiply(BigDecimal.ONE.add(taxPoint)).setScale(2,BigDecimal.ROUND_HALF_UP);
            log.info("订单【{}】，人民币汇率【{}】，人民币货值【{}】计算香港出口海关税金，加税点后【{}】",impOrder.getDocNo(),cnyRate,cnyGoodsValue,customsTax);
            cost = new ImpOrderCost();
            cost.setExpenseSubjectId("A0036");
            cost.setCostClassify(CostClassifyEnum.DZF.getCode());//分类
            cost.setActualAmount(customsTax);//原始金额
            cost.setReceAmount(customsTax);//应收金额
            cost.setIsAutomatic(Boolean.TRUE);//系统生成
            cost.setOperator("系统");
            cost.setIsAllowEdit(Boolean.TRUE);//允许修改
            costList.add(cost);
        }
        //计算代理费
        BigDecimal serviceVal;
        //此处区分代理费计算模式
        if(Objects.equals(AgencyFeeModeEnum.of(impQuote.getAgencyFeeMode()),AgencyFeeModeEnum.EXPRESS)) {
            log.info("订单【{}】，采用按重量计算代理费模式",impOrder.getDocNo());
            CustomerExpressQuote customerExpressQuote = customerExpressQuoteService.getById(impQuote.getCustomerExpressQuoteId());
            Optional.ofNullable(customerExpressQuote).orElseThrow(()->new ServiceException("客户还未创建代理费报价信息"));
            List<CustomerExpressQuoteMember> customerExpressQuoteMembers =  customerExpressQuoteMemberService.findByQuoteId(customerExpressQuote.getId());
            List<ImpOrderMemberVO> weightOrderMembers = impOrderMemberVOS.stream().filter(r->Objects.nonNull(r.getGrossWeight())).collect(Collectors.toList());
            BigDecimal totalGrossWeight = weightOrderMembers.stream().map(ImpOrderMemberVO::getGrossWeight).reduce(BigDecimal.ZERO,BigDecimal::add).setScale(0, RoundingMode.CEILING);
            serviceVal = ExpressQuoteUtil.calculate(totalGrossWeight,customerExpressQuote,customerExpressQuoteMembers);
        } else {
            switch (TaxTypeEnum.of(impQuote.getTaxType())){
                case AFTER_TAX://税后
                    //代理费 = 保留2位小数四舍五入（固定服务费 + (报关总价 * 海关汇率 + 关税 + 增值税 + 消费税) * 代理费率）
                    serviceVal = impQuote.getBasePrice().add((impOrder.getDecTotalPrice().multiply(impOrder.getCustomsRate()).add(ototalTariffRateVal).add(ototalAddedTaxTateVal).add(ototalExciseTaxVal)).multiply(impQuote.getServiceRate().divide(BigDecimal.valueOf(100)))).setScale(2,BigDecimal.ROUND_HALF_UP);
                    break;
                case PRE_TAX://税前
                    //代理费 = 保留2位小数四舍五入（固定服务费 + 报关总价 * 海关汇率 * 代理费率）
                    serviceVal = impQuote.getBasePrice().add(impOrder.getDecTotalPrice().multiply(impOrder.getCustomsRate()).multiply(impQuote.getServiceRate().divide(BigDecimal.valueOf(100)))).setScale(2,BigDecimal.ROUND_HALF_UP);
                    break;
                default:
                    throw new ServiceException("代理费计算未定义税前/税后");
            }
            //最低消费
            if(serviceVal.compareTo(impQuote.getMinCost())==-1){
                serviceVal = impQuote.getMinCost();
            }
        }
        //加税点
        if(impQuote.getTaxIncluded()){
            serviceVal = serviceVal.multiply(BigDecimal.ONE.add(taxPoint)).setScale(2,BigDecimal.ROUND_HALF_UP);
        }
        ImpOrderCost cost = new ImpOrderCost();
        cost.setExpenseSubjectId("A0001");//科目
        cost.setCostClassify(CostClassifyEnum.DZF.getCode());//分类
        cost.setActualAmount(serviceVal);//原始金额
        cost.setReceAmount(serviceVal);//应收金额
        cost.setIsAutomatic(Boolean.TRUE);//系统生成
        cost.setOperator("系统");
        cost.setIsAllowEdit(Boolean.TRUE);//允许修改
        costList.add(cost);

        //删除原始系统生成的费用明细
        removeAutomaticOrderId(impOrder.getId());
        //根据订单获取非系统生成的杂费费用信息
        List<ImpOrderCost> dzfOrderCosts = impOrderCostMapper.findByNonAutomaticZfList(impOrder.getId());
        List<String> expenseSubjectIds = dzfOrderCosts.stream().map(ImpOrderCost::getExpenseSubjectId).collect(Collectors.toList());
        //保存生成的费用
        List<ImpOrderCost> saveCostList = Lists.newArrayList();
        if(CollUtil.isNotEmpty(costList)){
            Map<String,LocalDateTime> periodMap = Maps.newHashMap();
            //代杂费账期
            periodMap.put(CostClassifyEnum.DZF.getCode(), AccountUtils.agencyFeesPeriod(impOrder.getOrderDate(),impQuote));
            //税款账期
            periodMap.put(CostClassifyEnum.SK.getCode(), AccountUtils.taxFeesPeriod(impOrder.getOrderDate(),impQuote));
            costList.stream().forEach(co ->{
                //费用未被人工调整
                if(!expenseSubjectIds.contains(co.getExpenseSubjectId())){
                    co.setId(snowflake.nextId());
                    co.setImpOrderId(impOrder.getId());
                    co.setAcceAmount(BigDecimal.ZERO);
                    co.setIsFirstWriteOff(Boolean.FALSE);
                    co.setIsLock(Boolean.FALSE);
                    co.setHappenDate(impOrder.getOrderDate());
                    co.setPeriodDate(periodMap.get(co.getCostClassify()));
                    co.setLateFeeDate((impQuote.getGraceDay()>0)?co.getPeriodDate().plusDays(impQuote.getGraceDay()):co.getPeriodDate());
                    co.setOverdueRate(impQuote.getOverdueRate());
                    saveCostList.add(co);
                }
            });
            if(CollUtil.isNotEmpty(dzfOrderCosts)){
                //修改人工调整的代杂费账期
                List<Long> costIds = dzfOrderCosts.stream().map(ImpOrderCost::getId).collect(Collectors.toList());
                LocalDateTime periodDate = periodMap.get(CostClassifyEnum.DZF.getCode());
                LocalDateTime lateFeeDate = (impQuote.getGraceDay()>0)?periodDate.plusDays(impQuote.getGraceDay()):periodDate;
                impOrderCostMapper.batchUpdatePeriodByIds(costIds,impOrder.getOrderDate(),periodDate,lateFeeDate,impQuote.getOverdueRate());
            }
        }
        if(CollUtil.isNotEmpty(saveCostList)){
            //批量保存
            savaBatch(saveCostList);
        }
        //更新订单明细
        impOrderMemberService.batchUpdatePartData(updateMemberList);
        //更新订单主单
        impOrderService.updateById(impOrder);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAutomaticOrderId(Long orderId) {
        try{
            ImpOrderCost delete = new ImpOrderCost();
            delete.setImpOrderId(orderId);//订单
            delete.setIsAutomatic(Boolean.TRUE);//系统生成
            super.remove(delete);
        }catch (Exception e){
            log.error("删除系统生成费用失败：",e);
            throw new ServiceException("系统费用已被核销，请检查");
        }
    }
    @Override
    public OrderCostInfoVO orderCostInfo(Long orderId) {
        return orderCostInfo(impOrderService.getById(orderId));
    }
    @Override
    public OrderCostInfoVO orderCostInfo(ImpOrder order) {
        TsfPreconditions.checkArgument(Objects.nonNull(order),new ServiceException("订单不存在"));
        OrderCostInfoVO vo = new OrderCostInfoVO();
        //收款未核销金额
        vo.setReceivablesVal(receiptAccountService.obtainCustomerReceipts(order.getCustomerId()));
        //订单总费用
        vo.setOrderTotalCost(orderCostTotal(order.getId()));
        //进口本单应支付金额 (税杂费)
        vo.setOrderPayVal(orderCostPayTotal(order.getId()));
        //客户逾期金额
        vo.setTotalArrearsVal(customerArrearsTotal(order.getCustomerId()));
        //获取客户税款占用额度（应收税杂费未核销金额）
        BigDecimal taxCostTotal = customerTaxTotal(order.getCustomerId());
        //查询客户税款分配额度
        Customer customer = customerService.getById(order.getCustomerId());
        //当前客户可用税款额度
        BigDecimal taxQuota = customer.getTaxQuota();
        //收款未核销金额 - 应收税杂费未核销金额 - 本订单费用
        BigDecimal occupyQuota = vo.getReceivablesVal().subtract(taxCostTotal).subtract(vo.getOrderTotalCost()).setScale(2,BigDecimal.ROUND_HALF_UP);
        if(occupyQuota.compareTo(BigDecimal.ZERO)==-1){ //出现负数
            taxQuota = taxQuota.add(occupyQuota).setScale(2,BigDecimal.ROUND_HALF_UP);
        }
        vo.setTaxOccupyVal(taxQuota);
        //计算是否通过
        StringBuffer sb = new StringBuffer("");
        //收款未核销金额不足支付本次进口金额
        if(vo.getReceivablesVal().compareTo(vo.getOrderPayVal())==-1){
            BigDecimal payVal = vo.getReceivablesVal().subtract(vo.getOrderPayVal()).setScale(2,BigDecimal.ROUND_HALF_UP);
            sb.append(String.format("执行本次进口应支付：￥%s；",StringUtils.formatCurrency(payVal.abs())));
        }
        if(vo.getTotalArrearsVal().compareTo(BigDecimal.ZERO)==1){
            sb.append(String.format("客户存在逾期：￥%s；",StringUtils.formatCurrency(vo.getTotalArrearsVal())));
        }
        if(vo.getTaxOccupyVal().compareTo(BigDecimal.ZERO)==-1){
            sb.append("当前客户可用税款额度不足");
        }
        //是否可通过
        vo.setIsAdopt(StringUtils.isEmpty(sb.toString()));
        vo.setReason(sb.toString());

        //查询最近一条风控记录
        RiskApproval riskApproval = riskApprovalService.lastApproval(RiskApprovalDocTypeEnum.IMP_ORDER_AMOUNT_INSUFFICIENT_MOMEY.getCode(),order.getId().toString());
        if(Objects.nonNull(riskApproval)){
            vo.setFkAdopt(Objects.equals(RiskApprovalStatusEnum.APPROVED,RiskApprovalStatusEnum.of(riskApproval.getStatusId())));
            vo.setRiskControl(String.format("风控【%s】审核%s：%s",riskApproval.getApprover(),(vo.getFkAdopt()?"通过":"不通过"),StringUtils.removeSpecialSymbol(riskApproval.getApprovalInfo())));
            if(Objects.equals(vo.getFkAdopt(),Boolean.FALSE)){
                vo.setIsAdopt(Boolean.FALSE);
            }
        }
        return vo;
    }

    @Override
    public PaymentCostInfoVO paymentCostInfo(Long paymentId) {
        PaymentAccount paymentAccount = paymentAccountService.getById(paymentId);
        TsfPreconditions.checkArgument(Objects.nonNull(paymentAccount),new ServiceException("付款单不存在"));
        PaymentCostInfoVO vo = new PaymentCostInfoVO();
        //收款未核销金额
        vo.setReceivablesVal(receiptAccountService.obtainCustomerReceipts(paymentAccount.getCustomerId()));
        //付款单人民币金额
        vo.setAccountValueCny(paymentAccount.getAccountValueCny().add(paymentAccount.getBankFee()).setScale(2,BigDecimal.ROUND_HALF_UP));
        //本次付汇应支付金额(根据账期判断)
        LocalDateTime happenDate = LocalDateTimeUtils.convertLocalDate();//发生日期
        //获取付汇明细
        List<PaymentAccountMemberVO> memberVOS = paymentAccountMemberService.findByPaymentAccountId(paymentAccount.getId());
        BigDecimal accountValueCny = BigDecimal.ZERO;
        Map<Long, ImpQuote> quoteMap = Maps.newLinkedHashMap();
        for(PaymentAccountMemberVO mvo : memberVOS){
            //计算账期
            ImpQuote impQuote = quoteMap.get(mvo.getImpQuoteId());
            if(Objects.isNull(impQuote)){
                impQuote = impQuoteService.getById(mvo.getImpQuoteId());
                quoteMap.put(mvo.getImpQuoteId(),impQuote);
            }
            //到期日
            LocalDateTime periodDate = AccountUtils.goodFeesPeriod(happenDate,impQuote);
            if(!periodDate.isAfter(happenDate)){//账期小于等于发生日期(需要先支付)
                accountValueCny = accountValueCny.add(mvo.getAccountValueCny()).setScale(2,BigDecimal.ROUND_HALF_UP);
            }
        }
        vo.setPaymentAmountCny(accountValueCny.add(paymentAccount.getBankFee()).setScale(2,BigDecimal.ROUND_HALF_UP));
        //客户逾期金额
        vo.setTotalArrearsVal(customerArrearsTotal(paymentAccount.getCustomerId()));

        //获取客户货款占用额度（应收货款未核销金额）
        BigDecimal goodsCostTotal = customerGoodsTotal(paymentAccount.getCustomerId());
        //查询客户货款分配额度
        Customer customer = customerService.getById(paymentAccount.getCustomerId());
        //当前客户可用货款额度
        BigDecimal goodsQuota = customer.getGoodsQuota();
        //收款未核销金额 - 应收货款未核销金额 - 本次付汇金额
        BigDecimal occupyQuota = vo.getReceivablesVal().subtract(goodsCostTotal).subtract(vo.getAccountValueCny()).setScale(2,BigDecimal.ROUND_HALF_UP);
        if(occupyQuota.compareTo(BigDecimal.ZERO)==-1) { //出现负数
            goodsQuota = goodsQuota.add(occupyQuota).setScale(2,BigDecimal.ROUND_HALF_UP);
        }
        vo.setGoodOccupyVal(goodsQuota);

        //计算是否通过
        StringBuffer sb = new StringBuffer("");
        //收款未核销金额不足支付本次应付金额
        if(vo.getReceivablesVal().compareTo(vo.getPaymentAmountCny())==-1){
            BigDecimal payVal = vo.getReceivablesVal().subtract(vo.getPaymentAmountCny()).setScale(2,BigDecimal.ROUND_HALF_UP);
            sb.append(String.format("执行本次付汇应支付：￥%s；",StringUtils.formatCurrency(payVal.abs())));
        }
        if(vo.getTotalArrearsVal().compareTo(BigDecimal.ZERO)==1){
            sb.append(String.format("客户存在逾期：￥%s；",StringUtils.formatCurrency(vo.getTotalArrearsVal())));
        }
        if(vo.getGoodOccupyVal().compareTo(BigDecimal.ZERO)==-1){
            sb.append("当前客户可用货款额度不足");
        }
        //是否可通过
        vo.setIsAdopt(StringUtils.isEmpty(sb.toString()));
        vo.setReason(sb.toString());
        //查询最近一条风控记录
        RiskApproval riskApproval = riskApprovalService.lastApproval(RiskApprovalDocTypeEnum.PAYMENT_ACCOUNT_INSUFFICIENT_MOMEY.getCode(),paymentAccount.getId().toString());
        if(Objects.nonNull(riskApproval)){
            vo.setFkAdopt(Objects.equals(RiskApprovalStatusEnum.APPROVED,RiskApprovalStatusEnum.of(riskApproval.getStatusId())));
            vo.setRiskControl(String.format("风控【%s】审核%s：%s",riskApproval.getApprover(),(vo.getFkAdopt()?"通过":"不通过"),StringUtils.removeSpecialSymbol(riskApproval.getApprovalInfo())));
            if(Objects.equals(vo.getFkAdopt(),Boolean.FALSE)){
                vo.setIsAdopt(Boolean.FALSE);
            }
        }
        return vo;
    }

    @Override
    public BigDecimal orderCostTotal(Long orderId) {
        return impOrderCostMapper.orderCostTotal(orderId);
    }

    @Override
    public List<ImpOrderCostVO> obtainOrderNotLockCosts(Long orderId) {
        return impOrderCostMapper.obtainOrderNotLockCosts(orderId);
    }
    @Override
    public List<ImpOrderCostVO> orderCostList(Long orderId) {
        return impOrderCostMapper.orderCostList(orderId);
    }

    @Override
    public List<ImpOrderCost> findByOrderId(Long orderId) {
        if(Objects.isNull(orderId)){
            return Lists.newArrayList();
        }
        ImpOrderCost query = new ImpOrderCost();
        query.setImpOrderId(orderId);
        return super.list(query);
    }

    @Override
    public BigDecimal orderCostPayTotal(Long orderId) {
        return impOrderCostMapper.orderCostPayTotal(orderId);
    }

    @Override
    public BigDecimal customerArrearsTotal(Long customerId) {
        return impOrderCostMapper.customerArrearsTotal(customerId);
    }

    @Override
    public BigDecimal customerTaxTotal(Long customerId) {
        return impOrderCostMapper.customerTaxTotal(customerId);
    }

    @Override
    public BigDecimal customerGoodsTotal(Long customerId) {
        return impOrderCostMapper.customerGoodsTotal(customerId);
    }

    @Override
    public void impLockCost(Long orderId) {
        impOrderCostMapper.impLockCost(orderId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void impUnLockCost(List<Long> costIds) {
        if(CollUtil.isEmpty(costIds)){
            return;
        }
        impOrderCostMapper.impUnLockCost(costIds);
    }

    /**=
     * 比较值是否大于零
     * @param val
     * @return
     */
    private Boolean greaterZero(BigDecimal val){
        return val.compareTo(BigDecimal.ZERO) == 1;
    }

    /**=
     * 分析物料关税率
     * @param vo
     * @return
     */
    private BigDecimal analysisTariffRate(CustomsCodeVO vo,CountryVO country){
        BigDecimal rate = vo.getGtr();
        //最惠国
        if(country.getIsDiscount()){
            //有暂定优先取暂定
            rate =  Objects.nonNull(vo.getTit())?vo.getTit():vo.getMfntr();
        }
        return Objects.nonNull(rate)?rate:BigDecimal.ZERO;
    }

    @Override
    public List<ImpOrderCost> getAgentOrderCosts(Long orderId) {
        //排除科目费用 关税，增值税，消费税，货款，付汇手续费
        List<String> agentExpenseSubjectIds = Lists.newArrayList("A0002","A0003","A0004","A0005","A0006");
        TsfWeekendSqls wheres = TsfWeekendSqls.<ImpOrderCost>custom().andEqualTo(false,ImpOrderCost::getImpOrderId,orderId)
                .andNotIn(false,ImpOrderCost::getExpenseSubjectId,agentExpenseSubjectIds);
        return impOrderCostMapper.selectByExample(Example.builder(ImpOrderCost.class).where(wheres).build());
    }

    @Override
    public List<ImpOrderCost> getByMarkAndExpenseSubject(String mark, String expenseSubjectId) {
        TsfWeekendSqls wheres = TsfWeekendSqls.<ImpOrderCost>custom().andEqualTo(false,ImpOrderCost::getMark,mark)
                .andEqualTo(false,ImpOrderCost::getExpenseSubjectId,expenseSubjectId);
        return impOrderCostMapper.selectByExample(Example.builder(ImpOrderCost.class).where(wheres).build());
    }

    @Override
    public AdviceReceiptVO adviceReceipt(Long orderId) {
        ImpOrderDetailVO order = impOrderService.detail(orderId);
        //计算货款汇率，先判断是否有过付汇，如果有多个付汇，取其中一个就好
        List<BigDecimal> exchangeRates = paymentAccountService.getExchangeRateByImpOrderNo(order.getDocNo());
        if(CollUtil.isNotEmpty(exchangeRates)) {
            order.setGoodsRate(exchangeRates.get(0));
        } else {
            String rateTime = LocalDateTimeUtils.convertLocalAddHourMinuteStr(order.getOrderDate(),"09:30");
            RateTypeEnum rateType = RateTypeEnum.IMP_BANK_CHINA_SELL;
            BigDecimal goodsRate = DataCalling.getInstance().obtainBankChinaRate(order.getCurrencyId(), rateType.getCode(),rateTime);
            order.setGoodsRate(goodsRate);
        }
        SubjectSimpleVO subject = subjectService.getSimpleById(order.getSubjectId());
        List<ImpOrderMemberVO> members = impOrderMemberService.findOrderMaterielMember(orderId);
        List<SubjectBankVO> banks = subjectBankService.selectReceivablesBanks(order.getSubjectId());
        List<ImpOrderCostVO> costs = orderCostList(orderId);
        //查询订单付汇单
        List<PaymentOrderCostVO> orderCostVOList = paymentAccountMemberService.findByOrderPaymentCostId(orderId);
        List<String> notPayStatus = Arrays.asList(PaymentAccountStatusEnum.WAIT_SW_EXAMINE.getCode(),PaymentAccountStatusEnum.WAIT_FK_EXAMINE.getCode());
        orderCostVOList.stream().forEach(pcVo ->{
            if(notPayStatus.contains(pcVo.getStatusId())){
                ImpQuote impQuote = impQuoteService.getById(order.getImpQuoteId());
                ImpOrderCostVO costVO = new ImpOrderCostVO();
                costVO.setImpOrderId(order.getId());
                costVO.setImpOrderNo(order.getDocNo());
                costVO.setExpenseSubjectId("A0005");
                costVO.setExpenseSubjectName("货款");
                costVO.setCostClassify(CostClassifyEnum.HK.getCode());
                costVO.setActualAmount(pcVo.getAccountValueCny());
                costVO.setReceAmount(pcVo.getAccountValueCny());
                costVO.setAcceAmount(BigDecimal.ZERO);
                costVO.setHappenDate(pcVo.getAccountDate());
                //到期日
                LocalDateTime periodDate = AccountUtils.goodFeesPeriod(costVO.getHappenDate(),impQuote);
                costVO.setPeriodDate(periodDate);
                costVO.setLateFeeDate((impQuote.getGraceDay()>0)?costVO.getPeriodDate().plusDays(impQuote.getGraceDay()):costVO.getPeriodDate());
                costVO.setOverdueRate(impQuote.getOverdueRate());
                costVO.setMemo(String.format("付款申请单号：%s",pcVo.getDocNo()));
                costs.add(costVO);

                //存在付汇手续费
                if(pcVo.getBankFee().compareTo(BigDecimal.ZERO)==1){
                    List<PaymentAccountMemberVO> memberVOS = paymentAccountMemberService.findByPaymentAccountId(pcVo.getId());
                    if(CollectionUtil.isNotEmpty(memberVOS)&&Objects.equals(memberVOS.get(0).getImpOrderId(),order.getId())){
                        costVO = new ImpOrderCostVO();
                        costVO.setImpOrderId(order.getId());
                        costVO.setImpOrderNo(order.getDocNo());
                        costVO.setExpenseSubjectId("A0006");
                        costVO.setExpenseSubjectName("付汇手续费");
                        costVO.setCostClassify(CostClassifyEnum.HK.getCode());
                        costVO.setActualAmount(pcVo.getBankFee());
                        costVO.setReceAmount(pcVo.getBankFee());
                        costVO.setAcceAmount(BigDecimal.ZERO);
                        costVO.setHappenDate(pcVo.getAccountDate());
                        costVO.setPeriodDate(periodDate);
                        costVO.setLateFeeDate((impQuote.getGraceDay()>0)?costVO.getPeriodDate().plusDays(impQuote.getGraceDay()):costVO.getPeriodDate());
                        costVO.setOverdueRate(impQuote.getOverdueRate());
                        costVO.setMemo(String.format("付款申请单号：%s",pcVo.getDocNo()));
                        costs.add(costVO);
                    }
                }

            }
        });
        AdviceReceiptVO arVo = new AdviceReceiptVO();
        arVo.setSubject(subject);
        arVo.setOrder(order);
        arVo.setMembers(members);
        arVo.setCosts(costs);
        arVo.setBanks(banks);
        arVo.setPayments(orderCostVOList);
        return arVo;
    }

    @Override
    public Long exportAdviceReceiptExcel(Long orderId) {
        AdviceReceiptVO ar = adviceReceipt(orderId);
        ImpOrderDetailVO orderMain = ar.getOrder();
        String path = filePath + "temp/"+"scm"+"/advice_receipt/";
        String sysFileName = StrUtil.format("{}-{}.xls",orderMain.getDocNo(),System.currentTimeMillis());
        String fileName = StrUtil.format("收款通知书{}.xls",orderMain.getDocNo());
        ValidatorUtils.isTrueCall(!new File(path).exists(),()->new File(path).mkdirs());
        WritableWorkbook wwb = null;
        try {
            wwb = jxl.Workbook.createWorkbook(new File(path + sysFileName));
            WritableSheet sheet = wwb.createSheet(orderMain.getDocNo(), 0);
            WritableFont font18 = new WritableFont(WritableFont.ARIAL, 18, WritableFont.NO_BOLD, false);
            WritableFont font12 = new WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false);
//            WritableFont font12BOLD = new WritableFont(WritableFont.ARIAL, 10, WritableFont.BOLD, false);
            WritableCellFormat titleBold = new WritableCellFormat(font18);
            titleBold.setAlignment(Alignment.CENTRE);
            titleBold.setVerticalAlignment(VerticalAlignment.CENTRE);
            WritableCellFormat bold = new WritableCellFormat(font12);
            bold.setVerticalAlignment(VerticalAlignment.CENTRE);
            bold.setWrap(true);
            WritableCellFormat boldWrap = new WritableCellFormat(font12);
            boldWrap.setVerticalAlignment(VerticalAlignment.CENTRE);
            boldWrap.setWrap(true);
            WritableCellFormat cenBold = new WritableCellFormat(font12);
            cenBold.setAlignment(Alignment.CENTRE);
            cenBold.setVerticalAlignment(VerticalAlignment.CENTRE);
            WritableCellFormat boldBorder = new WritableCellFormat(font12);
            boldBorder.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN, jxl.format.Colour.BLACK);
            boldBorder.setWrap(false);
            boldBorder.setVerticalAlignment(VerticalAlignment.CENTRE);
            WritableCellFormat cenBoldBorder = new WritableCellFormat(font12);
            cenBoldBorder.setAlignment(Alignment.CENTRE);
            cenBoldBorder.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN, jxl.format.Colour.BLACK);
            cenBoldBorder.setWrap(true);
            cenBoldBorder.setVerticalAlignment(VerticalAlignment.CENTRE);
            Integer row = 0;
            sheet.setColumnView(0, 6);
            sheet.setColumnView(1, 26);
            sheet.setColumnView(2, 9);
            sheet.setColumnView(3, 9);
            sheet.setColumnView(4, 9);
            sheet.setColumnView(5, 6);
            sheet.setColumnView(6, 6);
            sheet.setColumnView(7, 8);
            sheet.setColumnView(8, 11);
            sheet.setColumnView(9, 9);
            sheet.setColumnView(10, 9);
            sheet.setColumnView(11, 9);
            SubjectSimpleVO subject = ar.getSubject();
            sheet.mergeCells(0, row, 11, row);
            sheet.addCell(new Label(0, row++, subject.getName(), titleBold));
            sheet.mergeCells(0, row, 11, row);
            sheet.addCell(new Label(0, row++, subject.getAddress(), cenBold));
            sheet.mergeCells(0, row, 11, row);
            sheet.addCell(new Label(0, row++, StrUtil.format("电话：{} 传真：{}",subject.getTel(),subject.getFax()), cenBold));
            sheet.mergeCells(0, row, 11, row);
            sheet.addCell(new Label(0, row++, "收款通知书", titleBold));
            row++;

            sheet.mergeCells(0, row, 2, row);
            sheet.addCell(new Label(0, row, StrUtil.format("客户名称:{}",orderMain.getCustomerName()), bold));
            sheet.mergeCells(3, row, 5, row);
            sheet.addCell(new Label(3, row, StrUtil.format("订单号:{}",orderMain.getDocNo()), bold));
            sheet.mergeCells(6, row, 8, row);
            sheet.addCell(new Label(6, row, StrUtil.format("订单日期:{}",LocalDateTimeUtils.formatShort(orderMain.getOrderDate())), bold));
            sheet.mergeCells(9, row, 11, row);
            sheet.addCell(new Label(9, row, StrUtil.format("结算汇率:{}",orderMain.getImpRate()), bold));
            row++;
            row++;
            sheet.addCell(new Label(0, row, "序号", cenBoldBorder));
            sheet.mergeCells(1, row, 2, row);
            sheet.addCell(new Label(1, row, "物料", cenBoldBorder));
            sheet.addCell(new Label(3, row, "单价", cenBoldBorder));
            sheet.addCell(new Label(4, row, "数量", cenBoldBorder));
            sheet.mergeCells(5, row, 6, row);
            sheet.addCell(new Label(5, row, "总价", cenBoldBorder));
            sheet.addCell(new Label(7, row, "币制", cenBoldBorder));
            sheet.addCell(new Label(8, row, "关税率", cenBoldBorder));
            sheet.addCell(new Label(9, row, "关税", cenBoldBorder));
            sheet.addCell(new Label(10, row, "增值税率", cenBoldBorder));
            sheet.addCell(new Label(11, row, "增值税", cenBoldBorder));

            List<ImpOrderMemberVO> members = ar.getMembers();
            BigDecimal tquantity = BigDecimal.ZERO;
            BigDecimal ttotalPrice = BigDecimal.ZERO;
            BigDecimal ttariffRateVal = BigDecimal.ZERO;
            BigDecimal taddedTaxTateVal = BigDecimal.ZERO;
            BigDecimal totalGrossWeight = BigDecimal.ZERO;
            BigDecimal treceAmount = BigDecimal.ZERO;
            for(int i=0;i<members.size();i++){
                row++;
                ImpOrderMemberVO member = members.get(i);
                sheet.addCell(new Label(0, row, ""+(i+1), cenBold));
                sheet.mergeCells(1, row, 2, row);
                sheet.addCell(new Label(1, row, StrUtil.format("{};{};{}",member.getName(),member.getBrand(),member.getModel()), boldBorder));
                sheet.addCell(new Label(3, row, member.getUnitPrice().toString(), boldBorder));
                sheet.addCell(new Label(4, row, member.getQuantity().toString(), boldBorder));
                sheet.mergeCells(5, row, 6, row);
                sheet.addCell(new Label(5, row, member.getTotalPrice().toString(), boldBorder));
                sheet.addCell(new Label(7, row, orderMain.getCurrencyName(), cenBold));
                sheet.addCell(new Label(8, row, StringUtils.removeSpecialSymbol(member.getTariffRate()), boldBorder));
                sheet.addCell(new Label(9, row, StringUtils.removeSpecialSymbol(member.getTariffRateVal()), boldBorder));
                sheet.addCell(new Label(10, row, StringUtils.removeSpecialSymbol(member.getAddedTaxTate()), boldBorder));
                sheet.addCell(new Label(11, row, StringUtils.removeSpecialSymbol(member.getAddedTaxTateVal()), boldBorder));
                tquantity = tquantity.add(member.getQuantity());
                ttotalPrice = ttotalPrice.add(member.getTotalPrice());
                if(Objects.nonNull(member.getTariffRateVal())){
                    ttariffRateVal = ttariffRateVal.add(member.getTariffRateVal());
                }
                if(Objects.nonNull(member.getAddedTaxTateVal())){
                    taddedTaxTateVal = taddedTaxTateVal.add(member.getAddedTaxTateVal());
                }
                totalGrossWeight = totalGrossWeight.add(member.getGrossWeight());
            }
            row++;
            sheet.mergeCells(0, row, 3, row);
            sheet.addCell(new Label(0, row, "合计：", boldBorder));
            sheet.addCell(new Label(4, row, tquantity.toString(), boldBorder));
            sheet.mergeCells(5, row, 6, row);
            sheet.addCell(new Label(5, row, ttotalPrice.toString(), boldBorder));
            sheet.addCell(new Label(7, row, "", boldBorder));
            sheet.addCell(new Label(8, row, "", boldBorder));
            sheet.addCell(new Label(9, row, ttariffRateVal.toString(), boldBorder));
            sheet.addCell(new Label(10, row, "", boldBorder));
            sheet.addCell(new Label(11, row, taddedTaxTateVal.toString(), boldBorder));
            row++;
            row++;
            sheet.mergeCells(0, row, 1, row);
            sheet.addCell(new Label(0, row, "费用科目", cenBoldBorder));
            sheet.mergeCells(2, row, 3, row);
            sheet.addCell(new Label(2, row, "费用金额(元)", cenBoldBorder));
            sheet.mergeCells(4, row, 5, row);
            sheet.addCell(new Label(4, row, "已付金额(元)", cenBoldBorder));
            sheet.mergeCells(6, row, 7, row);
            sheet.addCell(new Label(6, row, "账期日", cenBoldBorder));
            sheet.addCell(new Label(8, row, "逾期利率%", cenBoldBorder));
            sheet.mergeCells(9, row, 11, row);
            sheet.addCell(new Label(9, row, "费用说明", cenBoldBorder));
            List<ImpOrderCostVO> costs = ar.getCosts();
            for(ImpOrderCostVO cost : costs){
                row++;
                sheet.mergeCells(0, row, 1, row);
                sheet.addCell(new Label(0, row, cost.getExpenseSubjectName(), boldBorder));
                sheet.mergeCells(2, row, 3, row);
                sheet.addCell(new Label(2, row, cost.getReceAmount().toString(), boldBorder));
                sheet.mergeCells(4, row, 5, row);
                sheet.addCell(new Label(4, row, cost.getAcceAmount().toString(), boldBorder));
                sheet.mergeCells(6, row, 7, row);
                sheet.addCell(new Label(6, row, LocalDateTimeUtils.formatShort(cost.getPeriodDate()), boldBorder));
                sheet.addCell(new Label(8, row, StrUtil.format("{}%",cost.getOverdueRate()), boldBorder));
                sheet.mergeCells(9, row, 11, row);
                sheet.addCell(new Label(9, row, StringUtils.removeSpecialSymbol(cost.getMemo()), boldBorder));

                treceAmount = treceAmount.add(cost.getReceAmount());
            }
            List<PaymentOrderCostVO> payments = ar.getPayments();
            if(CollectionUtil.isNotEmpty(payments)){
                row++;
                row++;
                sheet.mergeCells(0, row, 1, row);
                sheet.addCell(new Label(0, row, "付款单号", cenBoldBorder));
                sheet.mergeCells(2, row, 3, row);
                sheet.addCell(new Label(2, row, "申请日期", cenBoldBorder));
                sheet.mergeCells(4, row, 5, row);
                sheet.addCell(new Label(4, row, "付汇汇率", cenBoldBorder));
                sheet.mergeCells(6, row, 7, row);
                sheet.addCell(new Label(6, row, "付款金额", cenBoldBorder));
                sheet.mergeCells(8, row, 9, row);
                sheet.addCell(new Label(8, row, "币制", cenBoldBorder));
                sheet.mergeCells(10, row, 11, row);
                sheet.addCell(new Label(10, row, "人民币金额", cenBoldBorder));

                for(PaymentOrderCostVO payment : payments){
                    row++;
                    sheet.mergeCells(0, row, 1, row);
                    sheet.addCell(new Label(0, row, payment.getDocNo(), boldBorder));
                    sheet.mergeCells(2, row, 3, row);
                    sheet.addCell(new Label(2, row, LocalDateTimeUtils.formatShort(payment.getAccountDate()), boldBorder));
                    sheet.mergeCells(4, row, 5, row);
                    sheet.addCell(new Label(4, row, payment.getExchangeRate().toString(), boldBorder));
                    sheet.mergeCells(6, row, 7, row);
                    sheet.addCell(new Label(6, row, payment.getAccountValue().toString(), boldBorder));
                    sheet.mergeCells(8, row, 9, row);
                    sheet.addCell(new Label(8, row, payment.getCurrencyName(), boldBorder));
                    sheet.mergeCells(10, row, 11, row);
                    sheet.addCell(new Label(10, row, payment.getAccountValueCny().toString(), boldBorder));
                }
            }
            row++;
            row++;
            sheet.mergeCells(0, row, 1, row);
            sheet.addCell(new Label(0, row, StrUtil.format("费用合计：{}元",treceAmount), bold));
            row++;
            row++;
            sheet.mergeCells(0, row, 11, row);
            sheet.addCell(new Label(0, row, "*注：费用信息以进口报关当日为准", bold));
            row++;
            sheet.mergeCells(0, row, 11, row);
            sheet.addCell(new Label(0, row, "请将以上应付款项按如下方式付至我司银行账户：", bold));
            List<SubjectBankVO> banks = ar.getBanks();
            for(int i=0;i<banks.size();i++){
                SubjectBankVO bank = banks.get(i);
                row++;
                sheet.mergeCells(0, row, 11, row);
                sheet.addCell(new Label(0, row, StrUtil.format("{} 开户行：{} 银行账号：{} {}",i+1,bank.getName(),bank.getAccount(),subject.getName()), bold));
            }

            wwb.write();
            ExportFileDTO exportFileDTO = new ExportFileDTO();
            exportFileDTO.setPath(path+File.separator + sysFileName);
            exportFileDTO.setFileName(fileName);
            exportFileDTO.setOnce(Boolean.TRUE);
            exportFileDTO.setOperator("系统自动生成");
            Long fileId = exportFileService.save(exportFileDTO);
            return fileId;
        } catch (Exception e) {
            log.error("导出进口收款通知书异常",e);
            throw new ServiceException("导出进口收款通知书异常，请稍后再试");
        } finally {
            if(null != wwb) {
                try {
                    wwb.close();
                } catch (Exception e) {
                    log.error("关闭Workbook异常",e);
                }
            }
        }
    }

    @Override
    public List<ImpOrderCostVO> canWriteOffList(Long customerId){
        return impOrderCostMapper.canWriteOffList(customerId);
    }

    @Override
    public List<ImpOrderCostVO> canWriteOffByOrderId(Long orderId) {
        return impOrderCostMapper.canWriteOffByOrderId(orderId);
    }

    @Override
    public List<ImpOrderCostVO> getAllCosts(Long orderId,String impOrderNo) {
        if(Objects.isNull(orderId) && StringUtils.isEmpty(impOrderNo)) {
            throw new ServiceException("订单id和订单号不能同时为空");
        }
        List<ImpOrderCostVO> list = impOrderCostMapper.getAllOrderCosts(orderId,impOrderNo);
        if(CollUtil.isNotEmpty(list)) {
            return list.stream().sorted(Comparator.comparing(ImpOrderCostVO::getExpenseSubjectId)).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    @Override
    public List<ImpOrderCost> getByExpenseSubject(Long orderId,String expenseSubjectId) {
        ImpOrderCost condition = new ImpOrderCost();
        condition.setImpOrderId(orderId);
        condition.setExpenseSubjectId(expenseSubjectId);
        return super.list(condition);
    }

    @Override
    public List<ImpOrderCostVO> checkGetAdjustCost(String impOrderNo,Boolean getCost) {
        ImpOrder impOrder = impOrderService.findByDocNo(impOrderNo);
        Optional.ofNullable(impOrder).orElseThrow(()->new ServiceException("订单号错误"));
        //审核通过的订单
        DomainStatus.getInstance().check(DomainOprationEnum.ORDER_ADJUST_COST,impOrder.getStatusId());
        TsfPreconditions.checkArgument(StringUtils.isEmpty(impOrder.getSalesContractNo()),new ServiceException("订单已经生成销售合同，不允许调整费用"));
        TsfPreconditions.checkArgument(StringUtils.isEmpty(impOrder.getInvoiceNo()),new ServiceException("订单已经生成发票申请，不允许调整费用"));
        if(Objects.equals(getCost,Boolean.TRUE)) {
            return getAllCosts(impOrder.getId(), null);
        }
        return Lists.newArrayList();
    }

    @Override
    public ImpOrderCostVO getSimpleCostInfo(Long impOrderCostId) {
        ImpOrderCost impOrderCost = super.getById(impOrderCostId);
        Optional.ofNullable(impOrderCost).orElseThrow(()->new ServiceException("订单费用信息不存在"));
        return beanMapper.map(impOrderCost,ImpOrderCostVO.class);
    }

    @Override
    public Long createOrderCostPdf(Long orderId) {
        AdviceReceiptVO adviceReceiptVO = this.adviceReceipt(orderId);
        String path = filePath + "temp/"+"scm"+"/advice_receipt/";
        String sysFileName = String.format("%s_%s.pdf",adviceReceiptVO.getOrder().getDocNo(),LocalDateTimeUtils.formatNow("yyyyMMddHHmmssSSS"));
        ExportFileDTO exportFileDTO = createPdf(adviceReceiptVO,path,sysFileName);
        Long fileId = exportFileService.save(exportFileDTO);
        return fileId;
    }

    @Override
    public Long createOrderCostExcel(Long orderId) {
        AdviceReceiptVO adviceReceiptVO = this.adviceReceipt(orderId);
        String path = filePath + "temp/"+"scm"+"/advice_receipt/";
        String sysFileName = String.format("%s_%s.xls",adviceReceiptVO.getOrder().getDocNo(),LocalDateTimeUtils.formatNow("yyyyMMddHHmmssSSS"));
        ExportFileDTO exportFileDTO = createExcel(adviceReceiptVO,path,sysFileName);
        Long fileId = exportFileService.save(exportFileDTO);
        return fileId;
    }

    public ExportFileDTO createExcel(AdviceReceiptVO vo,String path,String sysFileName) {
        try {
            SubjectSimpleVO subjectSimpleVO = vo.getSubject();
            ImpOrderDetailVO order = vo.getOrder();
            List<ImpOrderMemberVO> members = vo.getMembers();
            List<ImpOrderCostVO> costs = vo.getCosts();
            List<PaymentOrderCostVO> payments = vo.getPayments();
            List<SubjectBankVO> banks = vo.getBanks();

            String fileName = String.format("%s_ADVICE_RECEIPT.xls",order.getDocNo());
            new File(path).mkdirs();
            WritableWorkbook wwb = Workbook.createWorkbook(new File(path + sysFileName));
            WritableFont font18 = new WritableFont(WritableFont.ARIAL, 18, WritableFont.NO_BOLD, false);
            WritableFont font12 = new WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false);
            WritableFont font12Red = new WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false, UnderlineStyle.NO_UNDERLINE,Colour.RED);
            WritableCellFormat titleBold = new WritableCellFormat(font18);
            titleBold.setAlignment(Alignment.CENTRE);
            titleBold.setVerticalAlignment(VerticalAlignment.CENTRE);

            WritableCellFormat bold = new WritableCellFormat(font12);
            bold.setVerticalAlignment(VerticalAlignment.CENTRE);
            bold.setWrap(true);

            WritableCellFormat boldRed = new WritableCellFormat(font12Red);
            boldRed.setVerticalAlignment(VerticalAlignment.CENTRE);
            boldRed.setWrap(true);

            WritableCellFormat boldWrap = new WritableCellFormat(font12);
            boldWrap.setVerticalAlignment(VerticalAlignment.CENTRE);
            boldWrap.setWrap(true);

            WritableCellFormat cenBold = new WritableCellFormat(font12);
            cenBold.setAlignment(Alignment.CENTRE);
            cenBold.setVerticalAlignment(VerticalAlignment.CENTRE);

            WritableCellFormat boldBorder = new WritableCellFormat(font12);
            boldBorder.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN, jxl.format.Colour.BLACK);
            boldBorder.setWrap(false);
            boldBorder.setVerticalAlignment(VerticalAlignment.CENTRE);

            WritableCellFormat cenBoldBorder = new WritableCellFormat(font12);
            cenBoldBorder.setAlignment(Alignment.CENTRE);
            cenBoldBorder.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN, jxl.format.Colour.BLACK);
            cenBoldBorder.setWrap(true);
            cenBoldBorder.setVerticalAlignment(VerticalAlignment.CENTRE);

            WritableSheet sheet = wwb.createSheet("收款通知书", 0);
            Integer row = 0;
            sheet.setColumnView(0, 6);
            sheet.setColumnView(1, 26);
            sheet.setColumnView(2, 9);
            sheet.setColumnView(3, 9);
            sheet.setColumnView(4, 9);
            sheet.setColumnView(5, 6);
            sheet.setColumnView(6, 6);
            sheet.setColumnView(7, 8);
            sheet.setColumnView(8, 9);
            sheet.setColumnView(9, 9);
            sheet.setColumnView(10, 9);

            sheet.mergeCells(0, row, 10, row);
            sheet.addCell(new Label(0, row++, subjectSimpleVO.getName(), titleBold));
            sheet.mergeCells(0, row, 10, row);
            sheet.addCell(new Label(0, row++, subjectSimpleVO.getAddress(), cenBold));
            sheet.mergeCells(0, row, 10, row);
            sheet.addCell(new Label(0, row++, String.format("电话：%s 传真：%s",StringUtils.null2EmptyWithTrim(subjectSimpleVO.getTel()),StringUtils.null2EmptyWithTrim(subjectSimpleVO.getFax())), cenBold));
            sheet.mergeCells(0, row, 10, row);
            sheet.addCell(new Label(0, row++, "收款通知书", titleBold));

            sheet.mergeCells(0, row, 2, row);
            sheet.addCell(new Label(0, row, String.format("客户名称：%s",order.getCustomerName()), bold));
            sheet.mergeCells(3, row, 5, row);
            sheet.addCell(new Label(3, row, String.format("订单号：%s",order.getDocNo()), bold));
            sheet.mergeCells(6, row, 8, row);
            sheet.addCell(new Label(6, row, String.format("订单日期：%s", LocalDateTimeUtils.formatShort(order.getOrderDate())), bold));
            sheet.mergeCells(9, row, 10, row);
            sheet.addCell(new Label(9, row, String.format("结算汇率：%s", Objects.nonNull(order.getImpRate()) && order.getImpRate().compareTo(BigDecimal.ZERO) != 0? order.getImpRate().toString() : "", bold)));
            row++;
            row++;

            sheet.addCell(new Label(0, row, "序号", boldBorder));
            sheet.mergeCells(1, row, 2, row);
            sheet.addCell(new Label(1, row, "物料", boldBorder));
            sheet.addCell(new Label(3, row, "单价", boldBorder));
            sheet.addCell(new Label(4, row, "数量", boldBorder));
            sheet.addCell(new Label(5, row, "总价", boldBorder));
            sheet.addCell(new Label(6, row, "币制", boldBorder));
            sheet.addCell(new Label(7, row, "关税率", boldBorder));
            sheet.addCell(new Label(8, row, "关税", boldBorder));
            sheet.addCell(new Label(9, row, "增值税率", boldBorder));
            sheet.addCell(new Label(10, row, "增值税", boldBorder));
            BigDecimal tquantity = BigDecimal.ZERO;
            BigDecimal ttotalPrice = BigDecimal.ZERO;
            BigDecimal tgrossWeight = BigDecimal.ZERO;
            BigDecimal ttariffRateVal = BigDecimal.ZERO;
            BigDecimal taddedTaxTateVal = BigDecimal.ZERO;
            BigDecimal tcost = BigDecimal.ZERO;

            int ind = 1;
            for(ImpOrderMemberVO orderMember : members) {
                row++;
                sheet.addCell(new Label(0, row, String.valueOf(ind++), boldBorder));
                sheet.mergeCells(1, row, 2, row);
                sheet.addCell(new Label(1, row, orderMember.getName() + ";" + orderMember.getBrand() + ";" + orderMember.getModel() , boldBorder));
                sheet.addCell(new Label(3, row, StringUtils.formatCurrency(orderMember.getUnitPrice()), boldBorder));
                sheet.addCell(new Label(4, row, StringUtils.formatCurrency(orderMember.getQuantity()), boldBorder));
                sheet.addCell(new Label(5, row, StringUtils.formatCurrency(orderMember.getTotalPrice()), boldBorder));
                sheet.addCell(new Label(6, row, order.getCurrencyName(), boldBorder));
                if(Objects.isNull(orderMember.getTariffRate())){
                    sheet.addCell(new Label(7, row, "", boldBorder));
                }else{
                    sheet.addCell(new Label(7, row, StringUtils.formatCurrency(orderMember.getTariffRate()), boldBorder));
                }
                sheet.addCell(new Label(8, row, StringUtils.formatCurrency(Objects.isNull(orderMember.getTariffRateVal()) ? BigDecimal.ZERO : orderMember.getTariffRateVal()), boldBorder));
                if(Objects.isNull(orderMember.getAddedTaxTate())){
                    sheet.addCell(new Label(9, row, "", boldBorder));
                }else{
                    sheet.addCell(new Label(9, row, StringUtils.formatCurrency(orderMember.getAddedTaxTate()), boldBorder));
                }
                sheet.addCell(new Label(10, row, StringUtils.formatCurrency(Objects.isNull(orderMember.getAddedTaxTateVal()) ? BigDecimal.ZERO : orderMember.getAddedTaxTateVal()), boldBorder));

                tquantity = tquantity.add(orderMember.getQuantity()).setScale(2,BigDecimal.ROUND_HALF_UP);
                tgrossWeight = tgrossWeight.add(orderMember.getGrossWeight()).setScale(4,BigDecimal.ROUND_HALF_UP);
                ttotalPrice = ttotalPrice.add(orderMember.getTotalPrice()).setScale(2,BigDecimal.ROUND_HALF_UP);
                ttariffRateVal = ttariffRateVal.add(orderMember.getTariffRateVal()).setScale(2,BigDecimal.ROUND_HALF_UP);
                taddedTaxTateVal = taddedTaxTateVal.add(orderMember.getAddedTaxTateVal()).setScale(2,BigDecimal.ROUND_HALF_UP);
            }
            row++;
            sheet.mergeCells(0, row, 3, row);
            sheet.addCell(new Label(0, row, "合计：", boldBorder));
            sheet.addCell(new Label(4, row, StringUtils.formatCurrency(tquantity), boldBorder));
            sheet.addCell(new Label(5, row, StringUtils.formatCurrency(ttotalPrice), boldBorder));
            sheet.addCell(new Label(6, row, "", boldBorder));
            sheet.addCell(new Label(7, row, "", boldBorder));
            sheet.addCell(new Label(8, row, StringUtils.formatCurrency(ttariffRateVal), boldBorder));
            sheet.addCell(new Label(9, row, "", boldBorder));
            sheet.addCell(new Label(10, row, StringUtils.formatCurrency(taddedTaxTateVal), boldBorder));

            row++;
            row++;

            sheet.mergeCells(0, row, 1, row);
            sheet.addCell(new Label(0, row, "费用科目", boldBorder));
            sheet.mergeCells(2, row, 2, row);
            sheet.addCell(new Label(2, row, "费用金额(元)", boldBorder));
            sheet.mergeCells(3, row, 4, row);
            sheet.addCell(new Label(3, row, "已付金额(元)", boldBorder));
            sheet.mergeCells(5, row, 6, row);
            sheet.addCell(new Label(5, row, "账期日", boldBorder));
            sheet.mergeCells(7, row, 7, row);
            sheet.addCell(new Label(7, row, "逾期利率%", boldBorder));
            sheet.mergeCells(8, row, 10, row);
            sheet.addCell(new Label(8, row, "费用说明", boldBorder));

            for(ImpOrderCostVO cost : costs) {
                row++;
                sheet.mergeCells(0, row, 1, row);
                sheet.addCell(new Label(0, row, cost.getExpenseSubjectName(), boldBorder));
                sheet.mergeCells(2, row, 2, row);
                sheet.addCell(new Label(2, row, StringUtils.formatCurrency(cost.getReceAmount()), boldBorder));
                sheet.mergeCells(3, row, 4, row);
                sheet.addCell(new Label(3, row, StringUtils.formatCurrency(cost.getAcceAmount()), boldBorder));
                sheet.mergeCells(5, row, 6, row);
                sheet.addCell(new Label(5, row, LocalDateTimeUtils.formatShort(cost.getPeriodDate()), boldBorder));
                sheet.mergeCells(7, row, 7, row);
                sheet.addCell(new Label(7, row, StringUtils.formatCurrency(cost.getOverdueRate()), boldBorder));
                sheet.mergeCells(8, row, 10, row);
                sheet.addCell(new Label(8, row, cost.getMemo(), boldBorder));
                tcost = tcost.add(cost.getReceAmount()).setScale(2,BigDecimal.ROUND_HALF_UP);
            }

            if(CollUtil.isNotEmpty(payments)) {
                row++;
                row++;
                sheet.mergeCells(0, row, 1, row);
                sheet.addCell(new Label(0, row, "付款单号", boldBorder));
                sheet.mergeCells(2, row, 2, row);
                sheet.addCell(new Label(2, row, "申请日期", boldBorder));
                sheet.mergeCells(3, row, 4, row);
                sheet.addCell(new Label(3, row, "付汇汇率", boldBorder));
                sheet.mergeCells(5, row, 6, row);
                sheet.addCell(new Label(5, row, "付款金额", boldBorder));
                sheet.mergeCells(7, row, 7, row);
                sheet.addCell(new Label(7, row, "币制", boldBorder));
                sheet.mergeCells(8, row, 10, row);
                sheet.addCell(new Label(8, row, "人民币金额", boldBorder));

                for(PaymentOrderCostVO payment : payments) {
                    row++;
                    sheet.mergeCells(0, row, 1, row);
                    sheet.addCell(new Label(0, row, payment.getDocNo(), boldBorder));
                    sheet.mergeCells(2, row, 2, row);
                    sheet.addCell(new Label(2, row, LocalDateTimeUtils.formatShort(payment.getAccountDate()), boldBorder));
                    sheet.mergeCells(3, row, 4, row);
                    sheet.addCell(new Label(3, row, StringUtils.null2EmptyWithTrim(payment.getExchangeRate()), boldBorder));
                    sheet.mergeCells(5, row, 6, row);
                    sheet.addCell(new Label(5, row, StringUtils.formatCurrency(payment.getAccountValue()), boldBorder));
                    sheet.mergeCells(7, row, 7, row);
                    sheet.addCell(new Label(7, row, payment.getCurrencyName(), boldBorder));
                    sheet.mergeCells(8, row, 10, row);
                    sheet.addCell(new Label(8, row, StringUtils.formatCurrency(payment.getAccountValueCny()), boldBorder));
                }
            }

            row++;
            sheet.mergeCells(0, row, 1, row);
            sheet.addCell(new Label(0, row, String.format("毛重合计：%s",StringUtils.formatCurrency(tgrossWeight)), bold));

            row++;
            sheet.mergeCells(0, row, 1, row);
            sheet.addCell(new Label(0, row, String.format("应付合计：%s元",StringUtils.formatCurrency(tcost)), bold));
            row++;
            sheet.mergeCells(0, row, 11, row);
            sheet.addCell(new Label(0, row, "*注：费用信息以进口报关当日为准", boldRed));
            row++;
            sheet.mergeCells(0, row, 11, row);
            sheet.addCell(new Label(0, row, "请将以上应付款项按如下方式付至我司银行账户：", bold));
            for(int k = 0; k < banks.size(); k++) {
                row++;
                SubjectBankVO subjectBankVO = banks.get(k);
                sheet.mergeCells(0, row, 11, row);
                sheet.addCell(new Label(0, row, String.format("%s 开户行：%s 银行账号：%s %s",(k+1),subjectBankVO.getName(),subjectBankVO.getAccount(),subjectSimpleVO.getName()), bold));
            }
            wwb.write();
            wwb.close();

            ExportFileDTO exportFileDTO = new ExportFileDTO();
            exportFileDTO.setPath(path+"/"+sysFileName);
            exportFileDTO.setFileName(fileName);
            exportFileDTO.setOnce(Boolean.TRUE);
            exportFileDTO.setOperator("系统自动生成");
            return exportFileDTO;
        }  catch (Exception e){
            log.error(String.format("订单【%s】生成收款通知EXCEL失败：",vo.getOrder().getDocNo()),e);
            throw new ServiceException("导出收款通知EXCEL失败，请稍后再试");
        }
    }

    public ExportFileDTO createPdf(AdviceReceiptVO vo,String path,String sysFileName) {
        try{
            SubjectSimpleVO subjectSimpleVO = vo.getSubject();
            ImpOrderDetailVO order = vo.getOrder();
            List<ImpOrderMemberVO> members = vo.getMembers();
            List<ImpOrderCostVO> costs = vo.getCosts();
            List<PaymentOrderCostVO> payments = vo.getPayments();
            List<SubjectBankVO> banks = vo.getBanks();

            String fileName = String.format("%s_ADVICE_RECEIPT.pdf",order.getDocNo());
            new File(path).mkdirs();
            FileOutputStream out = new FileOutputStream(path+File.separator+sysFileName);
            //BaseFont bfCN = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H",true);
            BaseFont bfCN = BaseFont.createFont("/font/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            // 标题的字体
            Font chFont = new Font(bfCN, 20, Font.NORMAL, BaseColor.BLACK);
            // 正文的字体
            Font textFont = new Font(bfCN, 10, Font.NORMAL, BaseColor.BLACK);
            Font textBoldFont = new Font(bfCN, 10, Font.NORMAL, BaseColor.BLACK);
            Font redTextFont = new Font(bfCN, 10, Font.NORMAL, BaseColor.RED);
            Document document = new Document();
            PdfWriter.getInstance(document, out);
            document.open();
            //4.添加标题

            Paragraph  content = new Paragraph(subjectSimpleVO.getName(),chFont);
            content.setAlignment(Element.ALIGN_CENTER);
            document.add(content);

            content = new Paragraph(StringUtils.null2EmptyWithTrim(subjectSimpleVO.getAddress()),textFont);
            content.setAlignment(Element.ALIGN_CENTER);
            document.add(content);

            content = new Paragraph(String.format("电话：%s  传真：%s",(StringUtils.isNotEmpty(subjectSimpleVO.getTel())?subjectSimpleVO.getTel():"     "),(StringUtils.isNotEmpty(subjectSimpleVO.getFax())?subjectSimpleVO.getFax():"     ")),textFont);
            content.setAlignment(Element.ALIGN_CENTER);
            document.add(content);

            content = new Paragraph("收款通知书",chFont);
            content.setAlignment(Element.ALIGN_CENTER);
            document.add(content);

            document.add(new Paragraph(" ",textFont));

            PdfPTable table = new PdfPTable(8);
            table.getDefaultCell().setBorder(PdfPCell.NO_BORDER);
            table.setWidthPercentage(100);
            int[] array = {10, 28, 8, 14,10,12,10,8};
            table.setWidths(array);
            table.addCell(new Phrase("客户名称:",textFont));
            table.addCell(new Phrase(order.getCustomerName(),textFont));
            table.addCell(new Phrase("订单号:",textFont));
            table.addCell(new Phrase(order.getDocNo(),textFont));
            table.addCell(new Phrase("订单日期:",textFont));
            table.addCell(new Phrase(LocalDateTimeUtils.formatShort(order.getOrderDate()),textFont));
            table.addCell(new Phrase("结算汇率:",textFont));
            table.addCell(new Phrase(Objects.nonNull(order.getImpRate()) && order.getImpRate().compareTo(BigDecimal.ZERO) != 0? order.getImpRate().toString() : "",textFont));
            document.add(table);

            document.add(new Paragraph(" ",textFont));

            //订单明细
            PdfPTable productsTable = new PdfPTable(10);
            productsTable.setWidthPercentage(100);
            int[] productsArray = {5,25,8,9,10,7,8,8,10,10};
            productsTable.setWidths(productsArray);

            PdfPCell cell = new PdfPCell(new Phrase("序号",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("物料",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("单价",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("数量",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("总价",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("币制",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("关税率",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("关税",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("增值税率",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("增值税",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            productsTable.addCell(cell);

            BigDecimal tquantity = BigDecimal.ZERO;//总数量合计
            BigDecimal tgrossWeight = BigDecimal.ZERO;//总毛重合计
            BigDecimal ttotalPrice = BigDecimal.ZERO;//总价合计
            BigDecimal ttariffRateVal = BigDecimal.ZERO;//总关税合计
            BigDecimal taddedTaxTateVal = BigDecimal.ZERO;//总增值税合计
            for(int i=0;i<members.size();i++){
                ImpOrderMemberVO womm = members.get(i);
                tquantity = tquantity.add(womm.getQuantity()).setScale(2,BigDecimal.ROUND_HALF_UP);
                tgrossWeight = tgrossWeight.add(womm.getGrossWeight()).setScale(4,BigDecimal.ROUND_HALF_UP);
                ttotalPrice = ttotalPrice.add(womm.getTotalPrice()).setScale(2,BigDecimal.ROUND_HALF_UP);
                ttariffRateVal = ttariffRateVal.add(womm.getTariffRateVal()).setScale(2,BigDecimal.ROUND_HALF_UP);
                taddedTaxTateVal = taddedTaxTateVal.add(womm.getAddedTaxTateVal()).setScale(2,BigDecimal.ROUND_HALF_UP);

                productsTable.addCell(new Phrase((i+1)+"",textFont));
                productsTable.addCell(new Phrase(StringUtils.null2EmptyWithTrim(womm.getName()) + ";" + StringUtils.null2EmptyWithTrim(womm.getBrand()) + ";" + StringUtils.null2EmptyWithTrim(womm.getModel()),textFont));

                cell = new PdfPCell(new Phrase(StringUtils.removeSpecialSymbol(womm.getUnitPrice()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(womm.getQuantity()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(womm.getTotalPrice()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(order.getCurrencyName(),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                productsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.null2EmptyWithTrim(womm.getTariffRate()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(womm.getTariffRateVal()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.null2EmptyWithTrim(womm.getAddedTaxTate()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(womm.getAddedTaxTateVal()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                productsTable.addCell(cell);
            }

            cell = new PdfPCell(new Paragraph("合计 Total：",textFont));
            cell.setColspan(3);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(tquantity),textFont));
            cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            productsTable.addCell(cell);

            cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(ttotalPrice),textFont));
            cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            productsTable.addCell(cell);

            productsTable.addCell(new Phrase(" ",textFont));
            productsTable.addCell(new Phrase(" ",textFont));

            cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(ttariffRateVal),textFont));
            cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            productsTable.addCell(cell);

            productsTable.addCell(new Phrase(" ",textFont));

            cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(taddedTaxTateVal),textFont));
            cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
            productsTable.addCell(cell);

            document.add(productsTable);

            document.add(new Paragraph(" ",textFont));

            //费用明细
            PdfPTable costsTable = new PdfPTable(6);
            costsTable.setWidthPercentage(100);
            int[] costsArray = {11,13,13,12,11,40};
            costsTable.setWidths(costsArray);

            cell = new PdfPCell(new Phrase("费用科目",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            costsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("费用金额(元)",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            costsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("已付金额(元)",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            costsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("账期日",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            costsTable.addCell(cell);

            cell = new PdfPCell(new Phrase("逾期利率%",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            costsTable.addCell(cell);


            cell = new PdfPCell(new Phrase("费用说明",textBoldFont));
            cell.setHorizontalAlignment(Element.ALIGN_CENTER);
            costsTable.addCell(cell);

            BigDecimal allCost = BigDecimal.ZERO;
            for(int i=0;i<costs.size();i++){
                ImpOrderCostVO cost = costs.get(i);

                allCost = allCost.add(cost.getReceAmount()).setScale(2,BigDecimal.ROUND_HALF_UP);

                costsTable.addCell(new Phrase(StringUtils.null2EmptyWithTrim(cost.getExpenseSubjectName()),textFont));

                cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(cost.getReceAmount()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                costsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(cost.getAcceAmount()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                costsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(LocalDateTimeUtils.formatShort(cost.getPeriodDate()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                costsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(cost.getOverdueRate()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                costsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.null2EmptyWithTrim(cost.getMemo()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                costsTable.addCell(cell);
            }

            document.add(costsTable);

            document.add(new Paragraph(" ",textFont));

            //付汇信息
            PdfPTable paymentsTable = new PdfPTable(6);
            paymentsTable.setWidthPercentage(100);
            int[] paymentsArray = {18,18,18,18,10,18};
            paymentsTable.setWidths(paymentsArray);
            paymentsTable.addCell(new Phrase("付款单号",textBoldFont));
            paymentsTable.addCell(new Phrase("申请日期",textBoldFont));
            paymentsTable.addCell(new Phrase("付汇汇率",textBoldFont));
            paymentsTable.addCell(new Phrase("付款金额",textBoldFont));
            paymentsTable.addCell(new Phrase("币制",textBoldFont));
            paymentsTable.addCell(new Phrase("人民币金额",textBoldFont));

            for(int i=0;i<payments.size();i++){
                PaymentOrderCostVO payment = payments.get(i);

                cell = new PdfPCell(new Phrase(StringUtils.null2EmptyWithTrim(payment.getDocNo()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_LEFT);
                paymentsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(LocalDateTimeUtils.formatShort(payment.getAccountDate()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                paymentsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.null2EmptyWithTrim(payment.getExchangeRate()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                paymentsTable.addCell(cell);


                cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(payment.getAccountValue()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                paymentsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(payment.getCurrencyName(),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_CENTER);
                paymentsTable.addCell(cell);

                cell = new PdfPCell(new Phrase(StringUtils.formatCurrency(payment.getAccountValueCny()),textFont));
                cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
                paymentsTable.addCell(cell);
            }

            document.add(paymentsTable);

            content = new Paragraph("毛重合计：" + StringUtils.formatCurrency(tgrossWeight),textFont);
            content.setAlignment(Element.ALIGN_LEFT);
            document.add(content);

            content = new Paragraph("费用合计：" + StringUtils.formatCurrency(allCost),textFont);
            content.setAlignment(Element.ALIGN_LEFT);
            document.add(content);

            content = new Paragraph("*注：费用信息以进口报关当日为准",redTextFont);
            content.setAlignment(Element.ALIGN_LEFT);
            document.add(content);

            content = new Paragraph("请将以上应付款项按如下方式付至我司银行账户：",textFont);
            content.setAlignment(Element.ALIGN_LEFT);
            document.add(content);

            if(CollUtil.isNotEmpty(banks)) {
                for(int i = 0;i < banks.size();i++) {
                    SubjectBankVO bank = banks.get(i);
                    content = new Paragraph((i + 1) + " 开户行：" + StringUtils.null2EmptyWithTrim(bank.getName())
                            + "， 银行账号：" + StringUtils.null2EmptyWithTrim(bank.getAccount())
                            + "， " + StringUtils.null2EmptyWithTrim(subjectSimpleVO.getName()),textFont);
                    content.setAlignment(Element.ALIGN_LEFT);
                    document.add(content);
                }
            }

            document.close();
            out.flush();
            out.close();
            ExportFileDTO exportFileDTO = new ExportFileDTO();
            exportFileDTO.setPath(path+"/"+sysFileName);
            exportFileDTO.setFileName(fileName);
            exportFileDTO.setOnce(Boolean.TRUE);
            exportFileDTO.setOperator("系统自动生成");
            return exportFileDTO;
        } catch (Exception e){
            log.error(String.format("订单【%s】生成收款通知PDF失败：",vo.getOrder().getDocNo()),e);
            throw new ServiceException("生成收款通知PDF失败");
        }
    }

}
